/*	Copyright (C) 2012  Claude Richard
 *
 *	This program is free software: you can redistribute it and/or modify
 *	it under the terms of the GNU General Public License as published by
 *	the Free Software Foundation, either version 3 of the License, or
 *	(at your option) any later version.
 *
 *	This program is distributed in the hope that it will be useful,
 *	but WITHOUT ANY WARRANTY; without even the implied warranty of
 *	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *	GNU General Public License for more details.
 *
 *	You should have received a copy of the GNU General Public License
 *	along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

#include "Algebra.hpp"
#include "AlgebraStruct.hpp"


/**
 * \brief		A physical system in Lagrangian Mechanics, which uses generalized coordinates.
 * \details		This class handles the computation of \f$ \ddot{\overrightarrow{x}} \f$
 *				given the generalized position vector \f$ \overrightarrow{x} \f$,
 *				the generalized velocity vector \f$ \dot{\overrightarrow{x}} \f$,
 *				and the generalized applied force vector \f$ \overrightarrow{Q} \f$.
 *				In order to use this class you need to implement the \a computeAB method,
 *				which computes the matrix \f$A\f$ and the vector \f$\overrightarrow{b}\f$ given
 *				\f$ \overrightarrow{x} \f$ and \f$ \dot{\overrightarrow{x}} \f$, such that
 *				the matrix form of the Lagrange equations can be written
 *				\f$ A \ddot{\overrightarrow{x}} + \overrightarrow{b} = \overrightarrow{Q} \f$.
 * \author		Claude Richard
 * \version		0.1
 * \date		2012
 * \warning		If the matrix \f$A\f$ that you compute in \a computeAB is not invertible
 *				for some values of \f$ \overrightarrow{x} \f$ and \f$ \dot{\overrightarrow{x}} \f$,
 *				then the program might crash when you call \a computeGeneralizedAcceleration.
 *				It is best to make sure that \f$A\f$ is invertible for all possible generalized position.
 * \invariant	The number of generalized coordinates \f$n\f$ in the system never changes.
 * \throw		Whenever you pass a vector of generalized position or velocity,
 *				it needs to have length \f$n\f$, otherwise this will throw an error.
 * \todo		Write and implement this class.
 */
class System {
	
public:
	
	/**
	 * \brief		Sets the number of generalized coordinates for the system.
	 * \details		This class's only piece of data stored is the number of generalized coordinates.
	 * \post		The object will have the number of generalized coordinates set.
	 * \param[in]	numGeneralizedCoordinates	The number of generalized coordinates.
	 * \throw		An error when \a numGeneralizedCoordinates <= 0.
	 */
	System( int numGeneralizedCoordinates );
	
	/**
	 * \brief		Computes the matrix \f$A\f$ and the vector \f$\overrightarrow{b}\f$ such that
	 *				the matrix form of the Lagrange equations can be written
	 *				\f$ A \ddot{\overrightarrow{x}} + \overrightarrow{b} = \overrightarrow{Q} \f$.
	 * \details		This function is used in the \a getGeneralizedAcceleration method.
	 * \pre			Both arguments must have length equal to \f$n\f$, the number of generalized coordinates.
	 * \param		generalizedPosition	The generalized position vector.
	 * \param		generalizedVelocity	The generalized velocity vector.
	 * \return		A struct containing \f$A(\overrightarrow{x},\dot{\overrightarrow{x}})\f$ and
	 *				\f$\overrightarrow{b}(\overrightarrow{x},\dot{\overrightarrow{x}})\f$ such that
	 *				the matrix form of the Lagrange equations can be written
	 *				\f$ A \ddot{\overrightarrow{x}} + \overrightarrow{b} = \overrightarrow{Q} \f$,
	 *				where \f$\overrightarrow{Q}\f$ is the generalized applied force on the system.
	 * \throw		An error if the length of either generalizedPosition or generalizedVelocity is not equal to
	 *				\f$n\f$, the number of generalized coordinates.
	 */
	virtual Matrix1Vector1 computeAB(
		const VectorND& generalizedPosition, const VectorND& generalizedVelocity ) = 0;
	
	/**
	 * \brief		Computes the generalized acceleration as a function of the generalized position, velocity, and force.
	 * \pre			All parameters must have length \f$n\f$, the number of generalized coordinates.
	 * \param		generalizedPosition	The generalized position vector.
	 * \param		generalizedVelocity	The generalized velocity vector.
	 * \param		generalizedForce	The generalized force vector.
	 * \return		The generalized acceleration when the position, velocity, and force are equal to the arguments.
	 * \throw		An error when either of the arguments does not have length \f$n\f$, the number of generalized coordinates.
	 * \todo		Implement this method.
	 */
	VectorND computeGeneralizedAcceleration(
		const VectorND& generalizedPosition, const VectorND& generalizedVelocity, const VectorND& generalizedForce );
	
	/**
	 * \brief		Computes the generalized acceleration as a function of the generalized position and velocity.
	 * \details		The applied force is assumed to be zero.
	 * \pre			All parameters must have length \f$n\f$, the number of generalized coordinates.
	 * \param		generalizedPosition	The generalized position vector.
	 * \param		generalizedVelocity	The generalized velocity vector.
	 * \return		The generalized acceleration when the position and velocity are equal to the arguments and the force is zero.
	 * \throw		An error when either of the arguments does not have length \f$n\f$, the number of generalized coordinates.
	 * \todo		Implement this method.
	 */
	VectorND computeGeneralizedAcceleration(
		const VectorND& generalizedPosition, const VectorND& generalizedVelocity );

protected:

	/// The number of generalized coordinates in the system.
	int mNumGeneralizedCoordinates;

};